package com.project.thisDatabase.base.service.impl;

import com.google.gson.reflect.TypeToken;
import com.project.annotation.enums.common.ConstBaseString;
import com.project.thisCommon.common.ConvertEntity;
import com.project.thisDatabase.base.DbExecutorBase;
import com.project.thisDatabase.base.db.SqlText;
import com.project.thisDatabase.base.mapper.BaseMapper;
import com.project.thisDatabase.base.model.*;
import com.project.thisDatabase.base.model.data.Condition;
import com.project.thisDatabase.base.model.entities.IntResultEntity;
import com.project.thisDatabase.base.model.entities.PageEntity;
import com.project.thisDatabase.base.service.ContextInterfaceBase;
import com.project.thisDatabase.base.service.ServiceInterfaceBase;
import com.project.thisDatabase.base.service.impl.pack.PkConvert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

public abstract class ServiceBase<T extends EntityBase, M extends BaseMapper<T>> implements ServiceInterfaceBase<T> {

    @Autowired(required = false)
    protected DbExecutorBase dbExecutorBase;

    @Autowired
    protected SqlText sqlText;

    @Autowired
    protected ContextInterfaceBase contextInterfaceBase;

    @Autowired
    protected M mapper;

    @Override
    public List<T> search(T entity){
        return mapper.search(entity);
    }

    @Override
    public List<T> searchPage(EntityPageBase<T> entity){
        Map<String,Object> map=createPageEntity(entity);
        return mapper.searchPage((T)map.get("entityItem"),(PageEntity)map.get("pageItem"));
    }

    @Override
    @Transactional
    public int update(T entity){
        Integer rtn = 0;
        T conditionItem = setKeys(entity);
        rtn += mapper.edit(conditionItem, entity);

        return rtn;
    }

    @Override
    @Transactional
    public int updateAll(T entity){
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        T conditionItem = setKeys(entity);

        if(null != loginUserItem) {
            entity.setModifyBy(loginUserItem.getUserCode());
            rtn += mapper.updateAll(conditionItem, entity);
        }

        return rtn;
    }

    @Override
    @Transactional
    public int updateList(List<T> entity){
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        if(null != loginUserItem) {
            for(T en : entity){
                T conditionItem = setKeys(en);
                en.setModifyBy(loginUserItem.getUserCode());
                rtn += mapper.edit(conditionItem, en);
            }
        }

        return rtn;
    }

    @Override
    @Transactional
    public int updateSearchList(BaseUpdateEntity<T> entity){
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        T conditionItem = entity.getCondition();
        T contentItem = entity.getContent();

        if(null != loginUserItem) {
            contentItem.setModifyBy(loginUserItem.getUserCode());
            rtn += mapper.edit(conditionItem, contentItem);
        }

        return rtn;
    }

    @Override
    @Transactional
    public int deleteList(BaseUpdateEntity<T> entity){
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        T conditionItem = entity.getCondition();
        T contentItem = entity.getContent();

        conditionItem.setStatus(ConstBaseString.YES);
        contentItem.setStatus(ConstBaseString.NO);
        contentItem.setDelCode(UUID.randomUUID().toString());

        if(null != loginUserItem) {
            contentItem.setModifyBy(loginUserItem.getUserCode());
            rtn += mapper.edit(conditionItem, contentItem);
        }

        return rtn;
    }

    @Override
    @Transactional
    public int insert(T entity) {
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        if(null != loginUserItem) {
            entity.setCreateBy(loginUserItem.getUserName());
            rtn += mapper.add(entity);
        }

        return rtn;
    }

    @Override
    @Transactional
    public int insertOrUpdate(T entity) {
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        if(null != loginUserItem) {
            entity.setCreateBy(loginUserItem.getUserName());
            entity.setOwnId(loginUserItem.getId());
            rtn += mapper.insertOrUpdate(entity);
        }

        return rtn;
    }

    @Override
    @Transactional
    public int insertList(List<T> entity){
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        if(null != loginUserItem) {
            for(T en : entity){
                en.setCreateBy(loginUserItem.getUserName());
                rtn += mapper.add(en);
            }
        }

        return rtn;
    }

    @Override
    public IntResultEntity count(T entity) {
        return mapper.count(entity);
    }

    @Override
    public List<T> searchAut(T entity){
        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        if(null != loginUserItem) {
            entity.setOwnId(loginUserItem.getId());
            return mapper.searchAut(entity);
        }

        return null;
    }

    @Override
    public List<T> searchPageAut(EntityPageBase<T> entity){
        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        if(null != loginUserItem) {
            entity.getData().setOwnId(loginUserItem.getId());
            Map<String,Object> map=createPageEntity(entity);
            return mapper.searchPageAut((T)map.get("entityItem"),(PageEntity)map.get("pageItem"));
        }

        return null;
    }

    @Override
    @Transactional
    public int updateAut(T entity){
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        T conditionItem = setKeys(entity);

        if(null != loginUserItem) {
            conditionItem.setOwnId(loginUserItem.getId());
            entity.setModifyBy(loginUserItem.getUserCode());
            rtn += mapper.updateAut(conditionItem, entity);
        }

        return rtn;
    }

    @Override
    @Transactional
    public int updateListAut(List<T> entity){
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        if(null != loginUserItem) {
            for(T en : entity){
                T conditionItem = setKeys(en);
                conditionItem.setOwnId(loginUserItem.getId());
                en.setModifyBy(loginUserItem.getUserCode());
                rtn += mapper.updateAut(conditionItem, en);
            }
        }

        return rtn;
    }

    @Override
    @Transactional
    public int updateSearchListAut(BaseUpdateEntity<T> entity){
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        T conditionItem = entity.getCondition();
        T contentItem = entity.getContent();

        if(null != loginUserItem) {
            conditionItem.setOwnId(loginUserItem.getId());
            contentItem.setModifyBy(loginUserItem.getUserCode());
            rtn += mapper.updateAut(conditionItem, contentItem);
        }

        return rtn;
    }

    @Override
    @Transactional
    public int deleteListAut(BaseUpdateEntity<T> entity){
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        T conditionItem = entity.getCondition();
        T contentItem = entity.getContent();
        conditionItem.setStatus(ConstBaseString.YES);
        contentItem.setStatus(ConstBaseString.NO);
        contentItem.setDelCode(UUID.randomUUID().toString());

        if(null != loginUserItem) {
            conditionItem.setOwnId(loginUserItem.getId());
            contentItem.setModifyBy(loginUserItem.getUserCode());
            rtn += mapper.updateAut(conditionItem, contentItem);
        }

        return rtn;
    }

    @Override
    public IntResultEntity countAut(T entity) {
        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        if(null != loginUserItem) {
            entity.setOwnId(loginUserItem.getId());
            return mapper.countAut(entity);
        }

        return null;
    }

    @Override
    @Transactional
    public int insertAut(T entity){
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        if(null != loginUserItem) {
            entity.setOwnId(loginUserItem.getId());
            entity.setCreateBy(loginUserItem.getUserName());
            rtn += mapper.add(entity);
        }

        return rtn;
    }

    @Override
    @Transactional
    public int insertListAut(List<T> entity){
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        if(null != loginUserItem){
            for(T en : entity){
                en.setOwnId(loginUserItem.getId());
                en.setCreateBy(loginUserItem.getUserName());
                rtn += mapper.add(en);
            }
        }

        return rtn;
    }

    @Override
    @Transactional
    public int physicalDeleteAut(T entity) {
        Integer rtn = 0;

        UserInfoEntity loginUserItem = contextInterfaceBase.userInfo();
        if(null != loginUserItem) {
            entity.setOwnId(loginUserItem.getId());
            rtn += mapper.deleteAut(entity);
        }

        return rtn;
    }

    @Override
    public <U> List<T> search(Condition<U> item) throws Exception {
        return search(item, null);
    }

    @Override
    public <U> List<T> search(Condition<U> item, PageEntity page) throws Exception {
        return search(new String[] {"*"}, item, page);
    }

    @Override
    public <U> List<T> search(String[] cols, Condition<U> item, PageEntity page) throws Exception {
        T en = newInstance(item.getBody().getClass().newInstance());
        List pm = new ArrayList();
        Integer start = null, max = null;
        if (null != page) {
            start = page.getPageIndex();
            max = page.getPageSize();
        }
        String sql = sqlText.Select(cols, item, start, max, pm);
        List<T> ls = dbExecutorBase.search(sql, pm, en.getClass());

        return ls;
    }

    @Override
    @Transactional
    public <U> int update(T change, Condition<U> item) throws Exception {
        List pm = new ArrayList();
        String sql = sqlText.Update(change, item, pm);

        return dbExecutorBase.update(sql, pm);
    }

    @Override
    @Transactional
    public int change(T change) throws Exception {
        List pm = new ArrayList();
        String sql = sqlText.Insert(change, pm);

        return dbExecutorBase.insert(sql, pm);
    }

    @Override
    @Transactional
    public <U> int delete(Condition<U> item) throws Exception {
        List pm = new ArrayList();
        String sql = sqlText.Delete(item, pm);

        return dbExecutorBase.delete(sql, pm);
    }

    protected T newInstance(Object obj) {
        Type tp = ((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
//        Type tp = new TypeToken<T>() {}.getType();
        try {
            T res = ConvertEntity.copyEntity(obj, tp);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public T setKeys(T obj) {
        try {
            T res = (T) ConvertEntity.copyEntity(obj, obj.getClass(), new PkConvert());
            return res;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    protected Map<String,Object> createPageEntity(EntityPageBase<T> form) {
        Map<String,Object> map = new HashMap<String,Object>();
        T entity = newInstance(form.getData());
        map.put("entityItem", entity);
        map.put("pageItem", form.getPageEntity());
        return map;
    }

}
